// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
//
// ███╗   ██╗ ██████╗ ████████╗██╗ ██████╗███████╗
// ████╗  ██║██╔═══██╗╚══██╔══╝██║██╔════╝██╔════╝
// ██╔██╗ ██║██║   ██║   ██║   ██║██║     █████╗
// ██║╚██╗██║██║   ██║   ██║   ██║██║     ██╔══╝
// ██║ ╚████║╚██████╔╝   ██║   ██║╚██████╗███████╗
// ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚═╝ ╚═════╝╚══════╝
// ------------------------------------------------
//
// This file is automatically generated.
// Please do not edit these files manually.
//
// ------------------------------------------------

#nullable restore

using Elastic.Clients.Elasticsearch.Serverless.Core;
using Elastic.Clients.Elasticsearch.Serverless.Fluent;
using Elastic.Clients.Elasticsearch.Serverless.Serialization;
using Elastic.Transport;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Elastic.Clients.Elasticsearch.Serverless;

/// <summary>
/// <para>A geo bounding box. It can be represented in various ways:<br/>- as 4 top/bottom/left/right coordinates<br/>- as 2 top_left / bottom_right points<br/>- as 2 top_right / bottom_left points<br/>- as a WKT bounding box</para>
/// </summary>
[JsonConverter(typeof(GeoBoundsConverter))]
public sealed partial class GeoBounds : IComplexUnion<GeoBounds.Kind>
{
	public enum Kind
	{
		Coordinates,
		TopLeftBottomRight,
		TopRightBottomLeft,
		Wkt
	}

	private readonly Kind _kind;
	private readonly object _value;

	Kind IComplexUnion<Kind>.ValueKind => _kind;

	object IComplexUnion<Kind>.Value => _value;

	private GeoBounds(Kind kind, object value)
	{
		_kind = kind;
		_value = value;
	}

	public static GeoBounds Coordinates(Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds coordinates) => new(Kind.Coordinates, coordinates);

	public bool IsCoordinates => _kind == Kind.Coordinates;

	public bool TryGetCoordinates([NotNullWhen(true)] out Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds? coordinates)
	{
		coordinates = null;
		if (_kind == Kind.Coordinates)
		{
			coordinates = (Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds)_value;
			return true;
		}

		return false;
	}

	public static implicit operator GeoBounds(Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds coordinates) => GeoBounds.Coordinates(coordinates);

	public static GeoBounds TopLeftBottomRight(Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds topLeftBottomRight) => new(Kind.TopLeftBottomRight, topLeftBottomRight);

	public bool IsTopLeftBottomRight => _kind == Kind.TopLeftBottomRight;

	public bool TryGetTopLeftBottomRight([NotNullWhen(true)] out Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds? topLeftBottomRight)
	{
		topLeftBottomRight = null;
		if (_kind == Kind.TopLeftBottomRight)
		{
			topLeftBottomRight = (Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds)_value;
			return true;
		}

		return false;
	}

	public static implicit operator GeoBounds(Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds topLeftBottomRight) => GeoBounds.TopLeftBottomRight(topLeftBottomRight);

	public static GeoBounds TopRightBottomLeft(Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds topRightBottomLeft) => new(Kind.TopRightBottomLeft, topRightBottomLeft);

	public bool IsTopRightBottomLeft => _kind == Kind.TopRightBottomLeft;

	public bool TryGetTopRightBottomLeft([NotNullWhen(true)] out Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds? topRightBottomLeft)
	{
		topRightBottomLeft = null;
		if (_kind == Kind.TopRightBottomLeft)
		{
			topRightBottomLeft = (Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds)_value;
			return true;
		}

		return false;
	}

	public static implicit operator GeoBounds(Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds topRightBottomLeft) => GeoBounds.TopRightBottomLeft(topRightBottomLeft);

	public static GeoBounds Wkt(Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds wkt) => new(Kind.Wkt, wkt);

	public bool IsWkt => _kind == Kind.Wkt;

	public bool TryGetWkt([NotNullWhen(true)] out Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds? wkt)
	{
		wkt = null;
		if (_kind == Kind.Wkt)
		{
			wkt = (Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds)_value;
			return true;
		}

		return false;
	}

	public static implicit operator GeoBounds(Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds wkt) => GeoBounds.Wkt(wkt);
}

internal sealed class GeoBoundsConverter : MultiItemUnionConverter<GeoBounds, GeoBounds.Kind>
{
	public GeoBoundsConverter()
	{
		_types = new Dictionary<GeoBounds.Kind, Type> { { GeoBounds.Kind.Coordinates, typeof(Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds) }, { GeoBounds.Kind.TopLeftBottomRight, typeof(Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds) }, { GeoBounds.Kind.TopRightBottomLeft, typeof(Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds) }, { GeoBounds.Kind.Wkt, typeof(Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds) } };
		_factories = new Dictionary<Type, Func<object, GeoBounds>> { { typeof(Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds), o => GeoBounds.Coordinates((Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds)o) }, { typeof(Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds), o => GeoBounds.TopLeftBottomRight((Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds)o) }, { typeof(Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds), o => GeoBounds.TopRightBottomLeft((Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds)o) }, { typeof(Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds), o => GeoBounds.Wkt((Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds)o) } };
		_uniquePropertyToType = new Dictionary<string, Type> { { "bottom", typeof(Elastic.Clients.Elasticsearch.Serverless.CoordsGeoBounds) }, { "bottom_right", typeof(Elastic.Clients.Elasticsearch.Serverless.TopLeftBottomRightGeoBounds) }, { "bottom_left", typeof(Elastic.Clients.Elasticsearch.Serverless.TopRightBottomLeftGeoBounds) }, { "wkt", typeof(Elastic.Clients.Elasticsearch.Serverless.WktGeoBounds) } };
	}
}